package com.my.util;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import javax.crypto.Cipher;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;

public class RSACoder {

  public static final String KEY_ALGORITHM = "RSA";
  public static final String SIGNATURE_ALGORITHM = "MD5withRSA";
  private static final String PUBLIC_KEY = "RSAPublicKey";
  private static final String PRIVATE_KEY = "RSAPrivateKey";

  public static Map<String,Object> initKey() throws NoSuchAlgorithmException {

    KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM);
    keyPairGenerator.initialize(1024);
    KeyPair keyPair = keyPairGenerator.generateKeyPair();

    // 私钥
    RSAPrivateKey privateKey =(RSAPrivateKey) keyPair.getPrivate();

    // 公钥
    RSAPublicKey publicKey =(RSAPublicKey) keyPair.getPublic();

    Map<String,Object> keyMap = new HashMap<>(2);
    keyMap.put(PUBLIC_KEY,publicKey);
    keyMap.put(PRIVATE_KEY,privateKey);
    return keyMap;
  }

  /**
   * 获取公钥
   * @param keyMap
   * @return
   * @throws Exception
   */
  public static String getPublicKey(Map<String, Object> keyMap) throws Exception {
    //获得map中的公钥对象 转为key对象
    Key key = (Key) keyMap.get(PUBLIC_KEY);
    //编码返回字符串
    return encryptBASE64(key.getEncoded());
  }

  //获取私钥
  public static String getPrivateKey(Map<String, Object> keyMap) throws Exception {

    //获得map中的私钥对象 转为key对象
    Key key = (Key) keyMap.get(PRIVATE_KEY);
    //byte[] privateKey = key.getEncoded();
    //编码返回字符串
    return encryptBASE64(key.getEncoded());
  }

  //解码返回byte
  public static byte[] decryptBASE64(String key) throws Exception {
    return (new BASE64Decoder()).decodeBuffer(key);
  }

  //编码返回字符串
  public static String encryptBASE64(byte[] key) throws Exception {
    return (new BASE64Encoder()).encodeBuffer(key);
  }

  /**
   *  公钥加密
   * @param data
   * @param key
   * @return
   */
  public static byte[] encryptByPublicKey(byte[] data, String key) throws Exception {
    byte[] bytes = decryptBASE64(key);

    //获取公钥
    X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(bytes);
    KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
    PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);

    //对数据加密
    Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());// keyFactory.getAlgorithm() 的值都是RSA
    cipher.init(Cipher.ENCRYPT_MODE, publicKey);
    return cipher.doFinal(data);
  }

  /**
   * 私钥解密
   * @param encodedData
   * @param key
   * @return
   * @throws Exception
   */
  public static byte[] decryptByPrivateKey(byte[] encodedData, String key) throws Exception {
    //对秘钥解密
    byte[] bytes =  decryptBASE64(key);

    //取得私钥
    PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(bytes);
    KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
    PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
    //对数据解密
    Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); //keyFactory.getAlgorithm() 的值都是RSA
    cipher.init(Cipher.DECRYPT_MODE, privateKey);
    return cipher.doFinal(encodedData);
  }

  /**
   *  私钥签名
   * @param data
   * @param privateKey
   * @return
   * @throws Exception
   */
  public static String sign(byte[] data, String privateKey) throws Exception {
    // 解密由base64编码的私钥
    byte[] keyBytes = decryptBASE64(privateKey);

    // 构造PKCS8EncodedKeySpec对象
    PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);

    // KEY_ALGORITHM 指定的加密算法
    KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);

    // 取私钥匙对象
    PrivateKey priKey = keyFactory.generatePrivate(pkcs8KeySpec);

    // 用私钥对信息生成数字签名
    Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
    signature.initSign(priKey);
    signature.update(data);

    return encryptBASE64(signature.sign());


  }

  /**
   * 公钥验证签名
   * @param data
   * @param publicKey
   * @param sign
   * @return
   */
  public static Boolean verify(byte[] data, String publicKey, String sign) throws Exception {
    // 解密由base64编码的公钥
    byte[] keyBytes = decryptBASE64(publicKey);

    // 构造X509EncodedKeySpec对象
    X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);

    // KEY_ALGORITHM 指定的加密算法
    KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);

    // 取公钥匙对象
    PublicKey pubKey = keyFactory.generatePublic(keySpec);

    Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
    signature.initVerify(pubKey);
    signature.update(data);

    // 验证签名是否正常
    return signature.verify(decryptBASE64(sign));

  }
}
